from common.CommonNode import CommonNode
from common.CommonHeap import CommonHeap
from common.Utils import Utils


class Node(CommonNode):

    def __init__(self, size, start, obj):
        super().__init__(size, start, obj)
        self.marked = False
        self.forwarding = None

    def setChildren(self, children):
        self.children = children

    def setForwarding(self, forwarding):
        self.forwarding = forwarding

    def getForwarding(self):
        return self.forwarding

    def mark(self):
        self.marked = True
        return self

    def unMark(self):
        self.marked = False
        return self

    def isMarked(self):
        return self.marked

    def clear(self):
        super().clear()
        self.unMark()


class Heap:
    def __init__(self, size):
        self.heapStart = Node(size, 0, None)
        self.usedSize = 0
        self.size = size
        self.chunk = 1
        self.roots = []

    def __str__(self):
        return f"total: {self.size}, used: {self.usedSize}. chunk: {self.chunk}"

    def newObject(self, size, obj):
        nd, addChunk = CommonHeap.firstFit(self.heapStart, size, Node)
        if nd is None:
            raise Exception("分配失败")
        if addChunk:
            self.chunk += 1
        self.usedSize += size
        nd.setObj(obj)
        return nd

    def freeObject(self, node):
        self.usedSize -= node.getSize()
        decChunk = CommonHeap.freeObject(node)
        node.setObj(None)
        self.chunk -= decChunk

    def addToRoot(self, node):
        self.roots.append(node)

    def removeFromRoot(self, node):
        Utils.popIfExist(self.roots, node)

    def mark(self):
        CommonHeap.mark(self.roots)

    def zip(self):
        p = self.heapStart
        preMarked = None
        fstMarked = None
        used = 0
        chunk = 1
        while p is not None:
            if p.isMarked():
                chunk += 1
                fstMarked = fstMarked or p
                p.setStart(used)
                used += p.getSize()
                p.setPre(preMarked)
                if preMarked is not None:
                    preMarked.setNext(p)
                preMarked = p
            p = p.getNext()
        if preMarked is not None:
            freeNode = Node(self.size-used, used, None)
            freeNode.setPre(preMarked)
            preMarked.setNext(freeNode)
        if fstMarked is not None:
            self.heapStart = fstMarked
        self.usedSize = used
        self.chunk = chunk

    def gc(self):
        self.mark()
        self.zip()


if __name__ == '__main__':
    heap = Heap(1024)
    n0 = heap.newObject(12, "dasds")
    n1 = heap.newObject(12, "123")
    n2 = heap.newObject(12, "       c")
    # heap.addToRoot(n0)
    # heap.addToRoot(n2)
    heap.gc()
    print(heap)
